﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Text;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using KDS.Mes.Mes.Plans.Dtos;
using KDS.Mes.Authorization;
using KDS.Mes.Dto;
using KDS.Mes.Mes.AlcCodes;
using KDS.Mes.Mes.Lines;
using KDS.Mes.Mes.PlanModes;
using KDS.Mes.Mes.PlanDetails;
using System.Data.Entity.Core.Objects;
using Abp.Collections.Extensions;
using Abp.UI;

namespace KDS.Mes.Mes.Plans
{
    /// <summary>
    /// 计划信息服务实现
    /// </summary>
    [AbpAuthorize(AppPermissions.Pages_Plan_Plans)]
    public class PlanAppService : MesAppServiceBase, IPlanAppService
    {
        private readonly IRepository<Plan, int> _planRepository;
        private readonly IPlanListExcelExporter _planListExcelExporter;
        private readonly PlanManage _planManage;
        private readonly IRepository<AlcCode, int> _alcCodeRepository;
        private readonly IRepository<Line, int> _lineRepository;
        private readonly IRepository<PlanMode, int> _planModeRepository;
        private readonly IRepository<PlanDetail, int> _planDetailRepository;
        /// <summary>
        /// 构造方法
        /// </summary>
        public PlanAppService(
            IRepository<Plan, int> planRepository,
            PlanManage planManage, 
            IPlanListExcelExporter planListExcelExporter,
            IRepository<AlcCode, int> alcCodeRepository,
            IRepository<Line, int> lineRepository,
            IRepository<PlanMode, int> planModeRepository,
            IRepository<PlanDetail, int> planDetailRepository
  )
        {
            _planRepository = planRepository;
            _planManage = planManage;
            _planListExcelExporter = planListExcelExporter;
            _alcCodeRepository = alcCodeRepository;
            _lineRepository = lineRepository;
            _planModeRepository = planModeRepository;
            _planDetailRepository = planDetailRepository;
        }

        #region 计划信息管理


        public PagedResultDto<PlanListDto> GetPagedPlans(GetPlanInput input)
        {


            //初步过滤
            var query = _planRepository.GetAll().Join(_planDetailRepository.GetAll()

                        .WhereIf(input.SeatPositions[0].ToString() != "0", u => input.SeatPositions.Contains(u.SeatPositionId))
                        .WhereIf(!input.IsOnline01.ToString().IsNullOrEmpty(), u => u.IsOnline01 == input.IsOnline01)
                        .WhereIf(!input.IsOnline02.ToString().IsNullOrEmpty(), u => u.IsOnline02 == input.IsOnline02)
                        .WhereIf(!input.IsOnline03.ToString().IsNullOrEmpty(), u => u.IsOnline03 == input.IsOnline03)
                        .WhereIf(!input.IsOnline04.ToString().IsNullOrEmpty(), u => u.IsOnline04 == input.IsOnline04)
                        .WhereIf(!input.IsOnline05.ToString().IsNullOrEmpty(), u => u.IsOnline05 == input.IsOnline05)
                        .WhereIf(!input.IsOnline06.ToString().IsNullOrEmpty(), u => u.IsOnline06 == input.IsOnline06)
                        .WhereIf(!input.IsOnline07.ToString().IsNullOrEmpty(), u => u.IsOnline07 == input.IsOnline07)
                        .WhereIf(!input.IsOnline08.ToString().IsNullOrEmpty(), u => u.IsOnline08 == input.IsOnline08)
                        .WhereIf(!input.IsOnline09.ToString().IsNullOrEmpty(), u => u.IsOnline09 == input.IsOnline09)
                        .WhereIf(!input.IsOnline10.ToString().IsNullOrEmpty(), u => u.IsOnline10 == input.IsOnline10)
                        .WhereIf(!input.IsOnline10.ToString().IsNullOrEmpty(), u => u.IsOnline10 == input.IsOnline10),

                        pl => pl.Id, pd => pd.PlanId, (pl, pd) => new {
                            pl,
                            pd
                        })
                        .WhereIf(!input.LineId.ToString().IsNullOrEmpty(), u => u.pl.LineId.ToString() == input.LineId)
                        .WhereIf(!input.PlanModeId.ToString().IsNullOrEmpty(), u => u.pl.PlanModeId.ToString() == input.PlanModeId)
                        .WhereIf(!input.PlanDate.ToString().IsNullOrEmpty(), u => DbFunctions.TruncateTime(u.pl.PlanDate) == DbFunctions.TruncateTime(input.PlanDate))
                        .GroupBy(c => new { c.pl.Id,
                            c.pl.LineId,
                            c.pl.Line.LineName,
                            c.pl.AlcCodeId,
                            c.pl.AlcCode.ALCCode,
                            c.pl.PlanModeId,
                            c.pl.PlanMode.PlanModeCode,
                            c.pl.Priority,
                            c.pl.PlanQty,
                            c.pl.AfterSalePart,
                            c.pl.Remarks,
                            c.pl.PlanDate,
                            c.pl.LastModificationTime,
                            c.pl.CreationTime })
                        .Select(s => new PlanListDto
                        {
                            Id = s.Key.Id,
                            LineId = s.Key.LineId,
                            LineName = s.Key.LineName,
                            AlcCodeId = s.Key.AlcCodeId,
                            AlcCode = s.Key.ALCCode,
                            PlanModeId = s.Key.PlanModeId,
                            PlanModeCode = s.Key.PlanModeCode,
                            Priority = s.Key.Priority,
                            PlanQty = s.Key.PlanQty,
                            AfterSalePart = s.Key.AfterSalePart,
                            PlanDate = s.Key.PlanDate,
                            Remarks=s.Key.Remarks,
                            LastModificationTime = s.Key.LastModificationTime,
                            CreationTime = s.Key.CreationTime
                        });
            //.Select(o => o);

            //var query = from pl in _planRepository.GetAll()
            //            join pd in _planDetailRepository.GetAll() on pl.Id equals pd.PlanId
            //            //where pd.IsOnline01 == input.IsOnline01
            //            //group pl by pl into plan
            //            group new { pl.Id } by new { pl, pd } into g
            //            //select plan.Key;
            //            select g.Key;
            ////group pl by new { pl.Id, pl.Priority } into g
            ////select new { Id = g.Key, Count = g.Count() }
            ////select g;
            //query = query.WhereIf(!input.LineId.IsNullOrEmpty(), u => u.pl.LineId.ToString() == input.LineId)
            //             .WhereIf(!input.PlanModeId.IsNullOrEmpty(), u => u.pl.PlanModeId.ToString() == input.PlanModeId)
            //             .WhereIf(!input.PlanDate.ToString().IsNullOrEmpty(), u => DbFunctions.TruncateTime(u.pl.PlanDate) == DbFunctions.TruncateTime(input.PlanDate))
            //             .WhereIf(!input.IsOnline01.ToString().IsNullOrEmpty(), u => u.pd.IsOnline01 == input.IsOnline01)
            //             .WhereIf(!input.IsOnline02.ToString().IsNullOrEmpty(), u => u.pd.IsOnline02 == input.IsOnline02)
            //             .WhereIf(!input.IsOnline03.ToString().IsNullOrEmpty(), u => u.pd.IsOnline03 == input.IsOnline03)
            //             .WhereIf(!input.IsOnline04.ToString().IsNullOrEmpty(), u => u.pd.IsOnline04 == input.IsOnline04)
            //             .WhereIf(!input.IsOnline05.ToString().IsNullOrEmpty(), u => u.pd.IsOnline05 == input.IsOnline05)
            //             .WhereIf(!input.IsOnline06.ToString().IsNullOrEmpty(), u => u.pd.IsOnline06 == input.IsOnline06)
            //             .WhereIf(!input.IsOnline07.ToString().IsNullOrEmpty(), u => u.pd.IsOnline07 == input.IsOnline07)
            //             .WhereIf(!input.IsOnline08.ToString().IsNullOrEmpty(), u => u.pd.IsOnline08 == input.IsOnline08)
            //             .WhereIf(!input.IsOnline09.ToString().IsNullOrEmpty(), u => u.pd.IsOnline09 == input.IsOnline09)
            //             .WhereIf(!input.IsOnline10.ToString().IsNullOrEmpty(), u => u.pd.IsOnline10 == input.IsOnline10)

            //             .Select(s => new Plan
            //             {
            //                 //Plan = s.pl
            //                 Id = s.pl.Id,
            //                 LineId = s.pl.LineId,
            //                 AlcCodeId = s.pl.AlcCodeId,
            //                 PlanModeId = s.pl.PlanModeId,
            //                 Priority = s.pl.Priority,
            //                 PlanQty = s.pl.PlanQty,
            //                 PlanDate = s.pl.PlanDate,
            //                 LastModificationTime = s.pl.LastModificationTime,
            //                 CreationTime = s.pl.CreationTime
            //             }).ToList();
            //query = query.MapTo<Plan>();
            //排序
            //query = !string.IsNullOrEmpty(input.Sorting) ? query.OrderBy(x => x.Id) : query.OrderByDescending(t => t.CreationTime);
            query = query.OrderBy(t => t.PlanDate).ThenBy(t => t.Priority);
            //query = query.MapTo<List<Plan>>();
            //获取总数
            var tasksCount = query.Count();
            //默认的分页方式
            //var taskList = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();
            //ABP提供了扩展方法PageBy分页方式
            var taskList = query.Select(u=>u).PageBy(input).ToList();
            return new PagedResultDto<PlanListDto>(tasksCount, taskList.MapTo<List<PlanListDto>>());












            //////初步过滤
            ////var query = _planRepository.GetAll();

            //var query = from pl in _planRepository.GetAll()
            //            join pd in _planDetailRepository.GetAll() on pl.Id equals pd.PlanId
            //            //where pd.IsOnline01 == input.IsOnline
            //            group pl by pl into plan
            //            select plan.Key;
            ////group pl by new { pl.Id, pl.Priority } into g
            ////select new { Id = g.Key, Count = g.Count() }
            ////select g;
            //query = query.WhereIf(!input.LineId.IsNullOrEmpty(), u => u.LineId.ToString() == input.LineId)
            //            .WhereIf(!input.PlanModeId.IsNullOrEmpty(), u => u.PlanModeId.ToString() == input.PlanModeId)
            //            .WhereIf(!input.PlanDate.ToString().IsNullOrEmpty(), u => DbFunctions.TruncateTime(u.PlanDate) == DbFunctions.TruncateTime(input.PlanDate));
            ////排序
            ////query = !string.IsNullOrEmpty(input.Sorting) ? query.OrderBy(x => x.Id) : query.OrderByDescending(t => t.CreationTime);
            //query = query.OrderBy(t => t.PlanDate).ThenBy(t=>t.Priority);
            ////获取总数
            //var tasksCount = query.Count();
            ////默认的分页方式
            ////var taskList = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();
            ////ABP提供了扩展方法PageBy分页方式
            //var taskList = query.PageBy(input).ToList();
            //return new PagedResultDto<PlanListDto>(tasksCount, taskList.MapTo<List<PlanListDto>>());
        }

        /// <summary>
        /// 根据查询条件获取计划信息分页列表
        /// </summary>
        public async Task<PagedResultDto<PlanListDto>> GetPagedPlansAsync(GetPlanInput input)
        {

            var query = _planRepository.GetAll();
            //TODO:根据传入的参数添加过滤条件

            var planCount = await query.CountAsync();

            var plans = await query
            .OrderBy(input.Sorting)
            .PageBy(input)
            .ToListAsync();

            var planListDtos = plans.MapTo<List<PlanListDto>>();
            return new PagedResultDto<PlanListDto>(
            planCount,
            planListDtos
            );
        }

        /// <summary>
        /// 通过Id获取计划信息信息进行编辑或修改 
        /// </summary>
        public async Task<GetPlanForEditOutput> GetPlanForEditAsync(NullableIdDto<int> input)
        {
            var output = new GetPlanForEditOutput();

            PlanEditDto planEditDto;

            if (input.Id.HasValue)
            {
                var entity = await _planRepository.GetAsync(input.Id.Value);
                planEditDto = entity.MapTo<PlanEditDto>();
            }
            else
            {
                planEditDto = new PlanEditDto(); 
            }

            output.Plan = planEditDto;
            output.AlcCodes = _alcCodeRepository.GetAllList()
             .Select(c => new ComboboxItemDto(c.Id.ToString(), c.ALCCode) { IsSelected = output.Plan.AlcCodeId == c.Id })
             .ToList();
            output.Lines = _lineRepository.GetAllList()
              .Select(c => new ComboboxItemDto(c.Id.ToString(), c.LineName) { IsSelected = output.Plan.LineId == c.Id })
              .ToList();
            output.PlanModes = _planModeRepository.GetAllList()
              .Select(c => new ComboboxItemDto(c.Id.ToString(), c.PlanModeName) { IsSelected = output.Plan.PlanModeId == c.Id })
              .ToList();
            return output;
        }


        /// <summary>
        /// 通过指定id获取计划信息ListDto信息
        /// </summary>
        public async Task<PlanListDto> GetPlanByIdAsync(EntityDto<int> input)
        {
            var entity = await _planRepository.GetAsync(input.Id);

            return entity.MapTo<PlanListDto>();
        }







        /// <summary>
        /// 新增或更改计划信息
        /// </summary>
        public async Task CreateOrUpdatePlanAsync(CreateOrUpdatePlanInput input)
        {
            if (input.PlanEditDto.Id.HasValue)
            {
                await UpdatePlanAsync(input.PlanEditDto);
            }
            else
            {
                await CreatePlanAsync(input.PlanEditDto);
            }
        }

        /// <summary>
        /// 新增计划信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Plan_Plans_Create)]
        public virtual async Task<PlanEditDto> CreatePlanAsync(PlanEditDto input)
        {
            //TODO:新增前的逻辑判断，是否允许新增
            await CheckPriorityIfAlreadyExists(input);
            var entity = input.MapTo<Plan>();

            entity = await _planRepository.InsertAsync(entity);
            return entity.MapTo<PlanEditDto>();
        }

        /// <summary>
        /// 编辑计划信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Plan_Plans_Edit)]
        public virtual async Task UpdatePlanAsync(PlanEditDto input)
        {
            //TODO:更新前的逻辑判断，是否允许更新

            await CheckPriorityIfAlreadyExists(input);

            var entity = await _planRepository.GetAsync(input.Id.Value);
            input.MapTo(entity);

            await _planRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 删除计划信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Plan_PlanModes_Delete)]
        public async Task DeletePlanAsync(EntityDto<int> input)
        {
            //TODO:删除前的逻辑判断，是否允许删除
            await _planRepository.DeleteAsync(input.Id);
        }

        /// <summary>
        /// 批量删除计划信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Plan_PlanModes_Delete)]
        public async Task BatchDeletePlanAsync(List<int> input)
        {
            //TODO:批量删除前的逻辑判断，是否允许删除
            await _planRepository.DeleteAsync(s => input.Contains(s.Id));
        }


        private async Task CheckPriorityIfAlreadyExists(PlanEditDto input)
        {
            var existingStorage = await _planRepository.GetAll()
                .FirstOrDefaultAsync(l => l.PlanDate == input.PlanDate && 
                                          l.LineId == input.LineId && 
                                          l.PlanModeId==input.PlanModeId &&
                                          l.Priority==input.Priority);
            if (existingStorage == null)
            {
                return;
            }
            if (input.Id != null && existingStorage.Id == input.Id)
            {
                return;
                
            }
            throw new UserFriendlyException(L("ThisPlanAlreadyExists", input.LineId, input.PlanDate, input.PlanModeId, input.Priority));
        }

        #endregion


        #region 计划信息的Excel导出功能


        public async Task<FileDto> GetPlanToExcel(GetPlanInput input)
        {
            //var entities = await _planRepository.GetAll().WhereIf(!input.PlanModeId.IsNullOrEmpty(), u => u.PlanModeId.ToString() == input.PlanModeId).
            //    ToListAsync();

            var entities = await _planRepository.GetAll().Join(_planDetailRepository.GetAll()

                        .WhereIf(!input.SeatPositions.IsNullOrEmpty(), u => input.SeatPositions.Contains(u.SeatPositionId))
                        .WhereIf(!input.IsOnline01.ToString().IsNullOrEmpty(), u => u.IsOnline01 == input.IsOnline01)
                        .WhereIf(!input.IsOnline02.ToString().IsNullOrEmpty(), u => u.IsOnline02 == input.IsOnline02)
                        .WhereIf(!input.IsOnline03.ToString().IsNullOrEmpty(), u => u.IsOnline03 == input.IsOnline03)
                        .WhereIf(!input.IsOnline04.ToString().IsNullOrEmpty(), u => u.IsOnline04 == input.IsOnline04)
                        .WhereIf(!input.IsOnline05.ToString().IsNullOrEmpty(), u => u.IsOnline05 == input.IsOnline05)
                        .WhereIf(!input.IsOnline06.ToString().IsNullOrEmpty(), u => u.IsOnline06 == input.IsOnline06)
                        .WhereIf(!input.IsOnline07.ToString().IsNullOrEmpty(), u => u.IsOnline07 == input.IsOnline07)
                        .WhereIf(!input.IsOnline08.ToString().IsNullOrEmpty(), u => u.IsOnline08 == input.IsOnline08)
                        .WhereIf(!input.IsOnline09.ToString().IsNullOrEmpty(), u => u.IsOnline09 == input.IsOnline09)
                        .WhereIf(!input.IsOnline10.ToString().IsNullOrEmpty(), u => u.IsOnline10 == input.IsOnline10)
                        .WhereIf(!input.IsOnline10.ToString().IsNullOrEmpty(), u => u.IsOnline10 == input.IsOnline10),

                        pl => pl.Id, pd => pd.PlanId, (pl, pd) => new {
                            pl,
                            pd
                        })
                        .WhereIf(!input.LineId.IsNullOrEmpty(), u => u.pl.LineId.ToString() == input.LineId)
                        .WhereIf(!input.PlanModeId.IsNullOrEmpty(), u => u.pl.PlanModeId.ToString() == input.PlanModeId)
                        .WhereIf(!input.PlanDate.ToString().IsNullOrEmpty(), u => DbFunctions.TruncateTime(u.pl.PlanDate) == DbFunctions.TruncateTime(input.PlanDate))
                        .GroupBy(c => new {
                            c.pl.Id,
                            c.pl.LineId,
                            c.pl.Line.LineName,
                            c.pl.AlcCodeId,
                            c.pl.AlcCode.ALCCode,
                            c.pl.PlanModeId,
                            c.pl.PlanMode.PlanModeCode,
                            c.pl.Priority,
                            c.pl.PlanQty,
                            c.pl.AfterSalePart,
                            c.pl.Remarks,
                            c.pl.PlanDate,
                            c.pl.LastModificationTime,
                            c.pl.CreationTime
                        })
                        .Select(s => new PlanListDto
                        {
                            Id = s.Key.Id,
                            LineId = s.Key.LineId,
                            LineName = s.Key.LineName,
                            AlcCodeId = s.Key.AlcCodeId,
                            AlcCode = s.Key.ALCCode,
                            PlanModeId = s.Key.PlanModeId,
                            PlanModeCode = s.Key.PlanModeCode,
                            Priority = s.Key.Priority,
                            PlanQty = s.Key.PlanQty,
                            AfterSalePart = s.Key.AfterSalePart,
                            PlanDate = s.Key.PlanDate,
                            Remarks = s.Key.Remarks,
                            LastModificationTime = s.Key.LastModificationTime,
                            CreationTime = s.Key.CreationTime
                        }). ToListAsync();
            var dtos = entities.MapTo<List<PlanListDto>>();

            var fileDto = _planListExcelExporter.ExportPlanToFile(dtos);



            return fileDto;
        }


        #endregion










    }
}
